package com.chaodev.base.utils.security;


import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * 摘要算法,包含MD5(不安全),SHA-1(不安全),SHA2(SHA-224,SHA-256,SHA-384,SHA-512),JAVA8不支持SHA3,HMAC(MD5,SHA1,SHA2等)
 * @author zhangb
 */
public class DigestHelper {
    /**
     * 字符集默认UTF-8
     */
    private static final Charset CHARSET_TYPE= StandardCharsets.UTF_8;

    /**
     * md5加密
     * @param data 明文
     * @return 密文
     */
    public static String encodeMd5(byte[] data){
        byte[] encByte=null;
        try {
            encByte = MessageDigest.getInstance("md5").digest(
                    data);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("没有此等算法！");
        }
        String md5code = new BigInteger(1, encByte).toString(16);
        for (int i = 0; i < 32 - md5code.length(); i++) {
            md5code = "0" + md5code;
        }

        return md5code;
    }

    /**
     * md5加密
     * @param data 明文
     * @return 密文
     */
    public static String encodeMd5(String data){
        byte[] byteData=data.getBytes(CHARSET_TYPE);
        return encodeMd5(byteData);
    }

    /**
     * SHA-1摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha1(byte[] data) {
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
            mdTemp.update(data);
            byte[] md = mdTemp.digest();
            return byteToString(md);
        } catch (Exception e) {
            throw new RuntimeException("算法出错！");
        }
    }

    /**
     * SHA-1摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha1(String data) {
        byte[] byteData=data.getBytes(CHARSET_TYPE);
        return encodeSha1(byteData);
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha224(byte[] data) {
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA3-224");
            mdTemp.update(data);
            byte[] md = mdTemp.digest();
            return byteToString(md);
        } catch (Exception e) {
            throw new RuntimeException("算法出错！");
        }
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha224(String data) {
        byte[] byteData=data.getBytes(CHARSET_TYPE);
        return encodeSha224(byteData);
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha256(byte[] data){
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA-256");
            mdTemp.update(data);
            byte[] md = mdTemp.digest();
            return byteToString(md);
        } catch (Exception e) {
            throw new RuntimeException("算法出错！");
        }
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha256(String data) {
        byte[] byteData=data.getBytes(CHARSET_TYPE);
        return encodeSha256(byteData);
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha384(byte[] data){
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA-384");
            mdTemp.update(data);
            byte[] md = mdTemp.digest();
            return byteToString(md);
        } catch (Exception e) {
            throw new RuntimeException("算法出错！");
        }
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha384(String data) {
        byte[] byteData=data.getBytes(CHARSET_TYPE);
        return encodeSha384(byteData);
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha512(byte[] data){
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("SHA-512");
            mdTemp.update(data);
            byte[] md = mdTemp.digest();
            return byteToString(md);
        } catch (Exception e) {
            throw new RuntimeException("算法出错！");
        }
    }

    /**
     * SHA-2摘要算法
     * @param data 明文
     * @return 密文
     */
    public static String encodeSha512(String data) {
        byte[] byteData=data.getBytes(CHARSET_TYPE);
        return encodeSha512(byteData);
    }

    /**
     * Hmac-md5加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacMd5(byte[] data,byte[] key){
        return encodeHmac(data,key,"HmacMD5");
    }
    /**
     * Hmac-md5加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacMd5(String data,String key){
        byte[] dataByte=data.getBytes(CHARSET_TYPE);
        byte[] keyByte=key.getBytes(CHARSET_TYPE);
        return encodeHmac(dataByte,keyByte,"HmacMD5");
    }
    /**
     * Hmac-sha1加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha1(byte[] data,byte[] key){
        return encodeHmac(data,key,"HmacSHA1");
    }
    /**
     * Hmac-sha1加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha1(String data,String key){
        byte[] dataByte=data.getBytes(CHARSET_TYPE);
        byte[] keyByte=key.getBytes(CHARSET_TYPE);
        return encodeHmac(dataByte,keyByte,"HmacSHA1");
    }

    /**
     * Hmac-sha224加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha224(byte[] data,byte[] key){
        return encodeHmac(data,key,"HmacSHA224");
    }
    /**
     * Hmac-sha224加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha224(String data,String key){
        byte[] dataByte=data.getBytes(CHARSET_TYPE);
        byte[] keyByte=key.getBytes(CHARSET_TYPE);
        return encodeHmac(dataByte,keyByte,"HmacSHA224");
    }

    /**
     * Hmac-sha256加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha256(byte[] data,byte[] key){
        return encodeHmac(data,key,"HmacSHA256");
    }
    /**
     * Hmac-sha256加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha256(String data,String key){
        byte[] dataByte=data.getBytes(CHARSET_TYPE);
        byte[] keyByte=key.getBytes(CHARSET_TYPE);
        return encodeHmac(dataByte,keyByte,"HmacSHA256");
    }

    /**
     * Hmac-sha384加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha384(byte[] data,byte[] key){
        return encodeHmac(data,key,"HmacSHA384");
    }
    /**
     * Hmac-sha384加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha384(String data,String key){
        byte[] dataByte=data.getBytes(CHARSET_TYPE);
        byte[] keyByte=key.getBytes(CHARSET_TYPE);
        return encodeHmac(dataByte,keyByte,"HmacSHA384");
    }

    /**
     * Hmac-sha512加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha512(byte[] data,byte[] key){
        return encodeHmac(data,key,"HmacSHA512");
    }
    /**
     * Hmac-sha512加密
     * @param data 明文
     * @param key 秘钥
     * @return 密文
     */
    public static String encodeHmacSha512(String data,String key){
        byte[] dataByte=data.getBytes(CHARSET_TYPE);
        byte[] keyByte=key.getBytes(CHARSET_TYPE);
        return encodeHmac(dataByte,keyByte,"HmacSHA512");
    }

    /**
     *Hmac加密
     * @param data 明文
     * @param key 秘钥
     * @param encodeType 加密类型
     * @return
     */
    private static String encodeHmac(byte[] data,byte[] key,String encodeType){
        String s12="";
        try{
            SecretKey secretKey = new SecretKeySpec(key,encodeType);
            Mac hmacMD5 = Mac.getInstance(encodeType);
            hmacMD5.init(secretKey);
            hmacMD5.update(data);
            byte[] bytes = hmacMD5.doFinal();
            s12=byteToString(bytes);
        }
        catch (Exception e){
            e.printStackTrace();
        }
        return s12;
    }

    /**
     * 将字节数组转换为16进制
     * @param data 字节数组
     * @return 16进制字符串
     */
    private static String byteToString(byte[] data){
        StringBuilder stringBuilder=new StringBuilder(100);
        String temp="";
        for(byte bt:data){
            temp=Integer.toHexString(bt&0xFF);
            if(temp.length()==1){
                stringBuilder.append("0");
            }
            stringBuilder.append(temp);
        }
        return stringBuilder.toString();
    }

}
